import datetime
import inspect
import json
import os
import re
import socket
import subprocess
import sys
import time
import winreg

import requests
from PyQt5 import QtGui
from PyQt5.QtCore import Qt, pyqtSignal, QDateTime, QUrl
from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QDesktopServices, QStandardItem, QStandardItemModel
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox, QLabel, QAction, QDialog, QFormLayout, \
    QDateTimeEdit, QSpinBox, QDialogButtonBox, QComboBox, QVBoxLayout, QRadioButton, QTreeView
from playwright.sync_api import sync_playwright
from qt_material import apply_stylesheet

from Util.WorkerThread import WorkerThread
from Util.logging_config import setup_logger
from Util.zconfig import get_setting
from easyGET_window import Ui_MainWindow  # 导入生成的 UI 文件
import warnings

warnings.filterwarnings("ignore", category=DeprecationWarning)

class TimerDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("设置定时任务")
        # self.setGeometry(200, 200, 300, 200)

        # 创建布局
        layout = QFormLayout()

        # 创建日期时间选择控件
        self.start_time_edit = QDateTimeEdit(QDateTime.currentDateTime(), self)
        self.start_time_edit.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
        layout.addRow("定时任务启动时间", self.start_time_edit)

        # 创建运行间隔选择控件
        self.interval_spinbox = QSpinBox(self)
        self.interval_spinbox.setRange(1, 1440)  # 1分钟到1440分钟（即24小时）
        self.interval_spinbox.setValue(120)  # 默认30分钟
        layout.addRow("定时任务运行间隔(分钟)", self.interval_spinbox)

        # 创建浏览器选择部分
        self.browser_layout = QVBoxLayout()
        self.chrome_radio = QRadioButton("Google Chrome", self)
        self.edge_radio = QRadioButton("Microsoft Edge", self)

        # 默认选择谷歌浏览器
        self.chrome_radio.setChecked(True)
        self.browser_layout.addWidget(self.chrome_radio)
        self.browser_layout.addWidget(self.edge_radio)
        layout.addRow("选择浏览器", self.browser_layout)

        # 创建按钮框
        button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
        button_box.button(QDialogButtonBox.Ok).setText("确定")
        button_box.button(QDialogButtonBox.Cancel).setText("取消")
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)
        layout.addWidget(button_box)

        # 设置弹窗的布局
        self.setLayout(layout)

    def get_selected_browser(self):
        """获取用户选择的浏览器"""
        if self.chrome_radio.isChecked():
            return "chrome"
        elif self.edge_radio.isChecked():
            return "msedge"
        else:
            return "chrome"

    def get_start_time(self):
        return self.start_time_edit.dateTime()

    def get_interval(self):
        return self.interval_spinbox.value()


class SimpleApp(QMainWindow, Ui_MainWindow):
    log_signal = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.selected_table = None
        self.process = None
        self.selected_browser = 'Google'
        self.tb_timer_start_time = None  # 自动任务下次运行时间
        self.next_txt = None
        self.logger = None
        self.timer = None
        self.page = None
        self.context = None
        self.browser = None
        self.playwright = None
        self.work = None  # 初始化工作线程为 None
        self.selected_item=None

        self.setupUi(self)
        self.setup_logging()
        self.log_signal.connect(self.up_log)
        apply_stylesheet(self, theme='light_blue.xml', invert_secondary=True)
        self.load_log_file()
        self.tb_next_date.setStyleSheet("color: black;")
        # ====================================================== 设置窗口标题,版本信息=========================================================================
        self.setWindowTitle('easyGET抖音数据下载助手 V1.0')

    def load_log_file(self):
        '''
        加载运行日志
        :return:
        '''
        zbase_dir = os.getcwd()
        now = datetime.datetime.now()
        today = now.strftime('%Y-%m-%d')
        log_file = 'log/autoTasklog/tb/' + today + '.log'
        zauto_task_log_folder = os.path.join(zbase_dir, log_file)  # 日志存放的目录
        if os.path.exists(zauto_task_log_folder):
            try:
                with open(zauto_task_log_folder, 'r', encoding='utf-8') as file:  # 尝试使用 UTF-8 编码
                    log_content = file.read()
                    self.tb_log.setPlainText(log_content)
            except UnicodeDecodeError:  # 捕获解码错误
                try:
                    with open(zauto_task_log_folder, 'r', encoding='gbk') as file:  # 尝试使用 GBK 编码
                        log_content = file.read()
                        self.tb_log.setPlainText(log_content)
                except Exception as e:
                    self.tb_log.setPlainText(f"未读取到今天的日志文件")
        else:
            self.tb_log.setPlainText(f"未读取到今天的日志文件")
            # 使用 QTimer 延迟滚动到最后一行
        QTimer.singleShot(100,
                          lambda: self.tb_log.verticalScrollBar().setValue(self.tb_log.verticalScrollBar().maximum()))

    def up_log(self, message):
        self.tb_log.append(message)
        if 'ERROR' in message:
            response = self.send_wechat_message(message)

    def setup_logging(self):
        '''
        加载初始化数据:日志,账号列表,表格列表
        :return:
        '''
        #加载日志
        base_dir = os.getcwd()
        auto_task_log_folder = os.path.join(base_dir, 'log/autoTasklog/tb')
        if not os.path.exists(auto_task_log_folder):
            os.makedirs(auto_task_log_folder)
        self.logger = setup_logger("app_logger", auto_task_log_folder, self.log_signal)
        #加载账号
        # 创建账号模型
        model = QtGui.QStandardItemModel(self.tb_list_view)
        user_dict = get_setting('USER_NAME')
        # 添加数据到模型
        for user_id, user_name in user_dict.items():
            user = str(user_id) + '.' + user_name
            item = QtGui.QStandardItem(user)
            # 设置字体大小
            font = item.font()
            font.setPointSize(10)  # 设置字体大小
            item.setFont(font)
            model.appendRow(item)

        # 设置模型到 QListView
        self.tb_list_view.setModel(model)
        # 禁用双击事件
        self.tb_list_view.mouseDoubleClickEvent = self.ignore_double_click

        # 加载table
        # 创建table模型
        table_model = QtGui.QStandardItemModel(self.table_list_view)
        table_dict = get_setting('TASK_URL')
        # 添加数据到模型
        for index, table_name in enumerate(table_dict):
            zindex = index + 1
            tableStr = str(zindex) + '.' + table_name
            item = QtGui.QStandardItem(tableStr)
            # 设置字体大小
            font = item.font()
            font.setPointSize(10)  # 设置字体大小
            item.setFont(font)
            table_model.appendRow(item)

        # 设置模型到 QListView
        self.table_list_view.setModel(table_model)
        # 禁用双击事件
        self.table_list_view.mouseDoubleClickEvent = self.ignore_double_click

    def ignore_double_click(self, event):
        event.ignore()  # 忽略双击事件

    def get_chrome_path(self):
        try:
            # 打开注册表键
            with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
                                r'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe') as key:
                chrome_path, _ = winreg.QueryValueEx(key, None)
                return chrome_path
        except FileNotFoundError:
            return None

    def tb_login_btn(self):
        '''
        打开浏览器
        :return:
        '''
        func_name = inspect.currentframe().f_code.co_name
        msg = ''
        chrome_path = self.get_chrome_path()
        if chrome_path:
            self.logger.info("已定位谷歌浏览器")
        else:
            self.logger.info("未找到谷歌浏览器安装位置")
            return
        try:
            hostname = socket.gethostname()
            ip_address = socket.gethostbyname(hostname)
            try:
                # 获取当前选中的索引
                selected_indexes = self.tb_list_view.selectionModel().selectedIndexes()
                if selected_indexes:
                    # 取出选中的第一个项
                    index = selected_indexes[0]
                    selected_item = index.data()
                    cdp_url = get_setting(selected_item)
                    # 尝试通过 CDP 端口访问浏览器实例
                    response = requests.get(cdp_url)
                    if response.status_code == 200:
                        msg = '已有目标浏览器实例运行，已连接,请登录'
                else:
                    msg = '请先点击左侧选择账号'
            except requests.exceptions.RequestException:
                # 如果请求失败，说明没有浏览器实例在运行
                command = chrome_path + get_setting('START_CHROME')['PRDPATH']
                self.process = subprocess.Popen(command)
                time.sleep(5)
                msg = '已打开指定端口浏览器,请登录'
        except BaseException as e:
            msg = f'函数: {func_name}错误: {str(e)}'
        finally:
            self.logger.info(msg)

    def tb_start_btn(self):
        # 获取当前选中的索引
        selected_indexes = self.table_list_view.selectionModel().selectedIndexes()
        if selected_indexes:
            index = selected_indexes[0]
            self.selected_table = index.data()
        else:
            self.logger.warning('请在左侧选择要下载更新的表数据')
            return
        # 创建弹窗
        dialog = TimerDialog(self)
        if dialog.exec_():  # 如果点击了确定
            start_time = dialog.get_start_time()  # 获取定时任务开始时间
            interval = dialog.get_interval()  # 获取定时任务运行间隔（分钟）

            # 转换为毫秒
            interval_ms = interval * 60 * 1000

            # 设置定时任务开始时间
            self.tb_timer_start_time = start_time
            self.tb_interval = interval

            self.selected_browser = dialog.get_selected_browser()

            # 启动定时任务
            self.start_timer(interval_ms)

    def start_timer(self, interval_ms):
        # 获取当前时间与定时任务开始时间的时间差
        current_time = QDateTime.currentDateTime()
        time_diff = self.tb_timer_start_time.toMSecsSinceEpoch() - current_time.toMSecsSinceEpoch()

        # 如果定时任务的启动时间在未来，使用 QTimer.singleShot 延迟到指定时间
        if time_diff > 0:
            QTimer.singleShot(time_diff, self.start_worker)
            self.logger.info(
                f'定时任务已设置,启动时间:{self.tb_timer_start_time.toString("yyyy-MM-dd HH:mm:ss")},运行间隔:{self.tb_interval}分钟')
        else:
            # 如果指定时间已经过去，则立即执行
            self.start_worker()
            self.logger.info(
                f'定时任务已设置,启动时间{self.tb_timer_start_time.toString("yyyy-MM-dd HH:mm:ss")}在过去,立即执行任务,运行间隔:{self.tb_interval}分钟')

        # 启动定时器，在指定的间隔时间后定期执行任务
        if not self.timer:
            self.timer = QTimer()
            self.timer.timeout.connect(self.start_worker)

        # 启动定时器
        self.timer.start(interval_ms)

    def start_worker(self):
        self.logger.info('自动获取任务已开始...')
        self.work = WorkerThread(self.page, self.logger, self.selected_browser)
        self.work.finished.connect(self.on_finished)  # 连接信号
        self.work.upLog.connect(self.up_log)
        self.work.start()

        # 计算下次执行时间
        if self.tb_interval:
            zint = self.tb_interval * 60 * 1000
        else:
            zint = get_setting('TASK_INTERVAL')['TB_TASK'] * 1000  # 获取间隔（毫秒）
        self.tb_timer_start_time = self.tb_timer_start_time.addMSecs(zint)  # 更新计算下次执行时间
        self.next_txt = '下次运行时间:' + self.tb_timer_start_time.toString("yyyy-MM-dd HH:mm:ss")
        self.tb_next_date.setText(self.next_txt)  # 更新标签显示时间

    def tb_stop_btn(self):
        if self.timer is not None:
            self.timer.stop()  # 停止定时器
            self.timer = None  # 重置定时器
            self.tb_next_date.setText('下次运行时间:未设置')
            self.logger.info('定时任务已停止')

    def tb_save_btn(self):
        '''
        保存登录信息
        :return:
        '''
        # 获取当前选中的索引
        selected_indexes = self.tb_list_view.selectionModel().selectedIndexes()
        if selected_indexes:
            # 取出选中的第一个项
            index = selected_indexes[0]
            selected_item = index.data()
            self.selected_item = selected_item.split('.')[1]

        if self.selected_item is None:
            self.logger.info('未选择要保存的账号名!')
        else:
            try:
                playwright = sync_playwright().start()
                browser = playwright.chromium.connect_over_cdp(get_setting('CDPURL'))
                context = browser.contexts[0]
                page = context.pages[0]
                base_dir = os.getcwd()
                auto_cookie_folder = os.path.join(base_dir, 'cookies/tb')
                if not os.path.exists(auto_cookie_folder):
                    os.makedirs(auto_cookie_folder)
                cookie_path = auto_cookie_folder + '/' + self.selected_item + '.json'
                # 获取 cookies
                context.storage_state(path=cookie_path)
                msg = self.selected_item + '登录数据保存成功'
            except BaseException as e:
                msg = '保存' + self.selected_item + '登录数据失败,详情:' + str(e)
            finally:
                # 确保关闭上下文和浏览器
                if 'playwright' in locals() and playwright:
                    try:
                        if context:
                            context.close()  # 关闭上下文
                        if browser:
                            browser.close()  # 关闭浏览器
                        playwright.stop()  # 停止 Playwright 服务
                        if self.process:
                            self.process.terminate()  # 尝试正常终止进程
                            self.process.wait(timeout=5)  # 等待浏览器进程退出
                    except Exception as e:
                        msg = f"关闭浏览器或上下文失败: {e}"
                self.logger.info(msg)

    def on_finished(self):
        self.logger.info(f'-本次自动获取任务已结束')


def main():
    app = QApplication(sys.argv)
    app.setAttribute(Qt.AA_EnableHighDpiScaling)
    import warnings
    warnings.filterwarnings('ignore')

    window = SimpleApp()
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
